package com.login.client.oauth2;

import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ejlchina.okhttps.OkHttps;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.login.client.utils.HttpClientUtil;
import com.login.client.utils.HttpParamUtil;
import com.login.client.utils.SoMap;
import jakarta.servlet.http.HttpServletRequest;
import okhttp3.OkHttp;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;


/**
 * Sa-OAuth2 Client端 控制器
 *
 * @author click33
 */
@RestController
public class SaOAuthClientController {

    // 相关参数配置
    private final String clientId = "1001";                                // 应用id
    private final String clientSecret = "aaaa-bbbb-cccc-dddd-eeee";        // 应用秘钥
    private final String serverUrl = "http://sa-oauth-server.com:8000";    // 服务端接口


    // 进入首页
    @RequestMapping("/")
    public Object index(HttpServletRequest request) {
        request.setAttribute("uid", StpUtil.getLoginIdDefaultNull());
        return new ModelAndView("index.html");
    }

    // 根据Code码进行登录，获取 Access-Token 和 openid
    @RequestMapping("/codeLogin")
    public SaResult codeLogin(@RequestParam("code") String code) throws JsonProcessingException {
        // 调用Server端接口，获取 Access-Token 以及其他信息
        Map<String, Object> bodyParams = new HashMap<>();
        bodyParams.put("client_id", clientId);
        bodyParams.put("client_secret", clientSecret);
        bodyParams.put("grant_type", "authorization_code");
        bodyParams.put("code", code);
        String formData = HttpParamUtil.buildFormData(bodyParams);
        String s = HttpClientUtil.sendFormPostRequest(serverUrl + "/oauth2/token", formData);
        SoMap so = SoMap.getSoMap().setJsonString(s);
        System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));

        // code不等于200  代表请求失败
        if (so.getInt("code") != 200) {
            return SaResult.error(so.getString("msg"));
        }

        // 根据openid获取其对应的userId
        long uid = getUserIdByOpenid(so.getString("openid"));
        so.set("uid", uid);

        // 返回相关参数
        StpUtil.login(uid);
        return SaResult.data(so);
    }

    // 根据 Refresh-Token 去刷新 Access-Token
    @RequestMapping("/refresh")
    public SaResult refresh(@RequestParam("refreshToken") String refreshToken) throws JsonProcessingException {
        // 调用Server端接口，通过 Refresh-Token 刷新出一个新的 Access-Token
        Map<String, Object> bodyParams = new HashMap<>();
        bodyParams.put("client_id", clientId);
        bodyParams.put("client_secret", clientSecret);
        bodyParams.put("grant_type", "refresh_token");
        bodyParams.put("refresh_token", refreshToken);
        String formData = HttpParamUtil.buildFormData(bodyParams);
        String str = HttpClientUtil.sendFormPostRequest(serverUrl + "/oauth2/refresh", formData);

        SoMap so = SoMap.getSoMap().setJsonString(str);
        System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));

        // code不等于200  代表请求失败
        if (so.getInt("code") != 200) {
            return SaResult.error(so.getString("msg"));
        }

        // 返回相关参数
        return SaResult.data(so);
    }

    // 模式三：密码式-授权登录
    @RequestMapping("/passwordLogin")
    public SaResult passwordLogin(@RequestParam("username") String username, @RequestParam("password") String password) throws JsonProcessingException {
        // 模式三：密码式-授权登录
        Map<String, Object> bodyParams = new HashMap<>();
        bodyParams.put("client_id", clientId);
        bodyParams.put("client_secret", clientSecret);
        bodyParams.put("grant_type", "password");
        bodyParams.put("username", username);
        bodyParams.put("password", password);
        String formData = HttpParamUtil.buildFormData(bodyParams);
        String str = HttpClientUtil.sendFormPostRequest(serverUrl + "/oauth2/token", formData);
        SoMap so = SoMap.getSoMap().setJsonString(str);
        System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));

        // code不等于200  代表请求失败
        if (so.getInt("code") != 200) {
            return SaResult.error(so.getString("msg"));
        }

        // 根据openid获取其对应的userId
        long uid = getUserIdByOpenid(so.getString("openid"));
        so.set("uid", uid);

        // 返回相关参数
        StpUtil.login(uid);
        return SaResult.data(so);
    }

    // 模式四：获取应用的 Client-Token
    @RequestMapping("/clientToken")
    public SaResult clientToken() throws JsonProcessingException {
        // 调用Server端接口
        Map<String, Object> bodyParams = new HashMap<>();
        bodyParams.put("client_id", clientId);
        bodyParams.put("client_secret", clientSecret);
        bodyParams.put("grant_type", "client_credentials");
        String formData = HttpParamUtil.buildFormData(bodyParams);
        String str = HttpClientUtil.sendFormPostRequest(serverUrl + "/oauth2/client_token", formData);
        SoMap so = SoMap.getSoMap().setJsonString(str);
        System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));

        // code不等于200  代表请求失败
        if (so.getInt("code") != 200) {
            return SaResult.error(so.getString("msg"));
        }

        // 返回相关参数
        return SaResult.data(so);
    }

    // 注销登录
    @RequestMapping("/logout")
    public SaResult logout() {
        StpUtil.logout();
        return SaResult.ok();
    }

    // 根据 Access-Token 置换相关的资源: 获取账号昵称、头像、性别等信息
    @RequestMapping("/getUserinfo")
    public SaResult getUserinfo(@RequestParam("accessToken") String accessToken) throws JsonProcessingException {
        // 调用Server端接口，查询开放的资源
        Map<String, Object> bodyParams = new HashMap<>();
        bodyParams.put("client_id", clientId);
        bodyParams.put("client_secret", clientSecret);
        bodyParams.put("grant_type", "client_credentials");
        bodyParams.put("access_token", accessToken);
        String formData = HttpParamUtil.buildFormData(bodyParams);
        String str = HttpClientUtil.sendFormPostRequest(serverUrl + "/oauth2/userinfo", formData);
        SoMap so = SoMap.getSoMap().setJsonString(str);
        System.out.println("返回结果: " + new ObjectMapper().writeValueAsString(so));

        // code不等于200  代表请求失败
        if (so.getInt("code") != 200) {
            return SaResult.error(so.getString("msg"));
        }

        // 返回相关参数 (data=获取到的资源 )
        return SaResult.data(so);
    }

    // 全局异常拦截
    @ExceptionHandler
    public SaResult handlerException(Exception e) {
        e.printStackTrace();
        return SaResult.error(e.getMessage());
    }


    // ------------ 模拟方法 ------------------
    // 模拟方法：根据openid获取userId
    private long getUserIdByOpenid(String openid) {
        // 此方法仅做模拟，实际开发要根据具体业务逻辑来获取userId
        return 10001;
    }

}
